﻿/**************************************************************************
创建时间:	2013/5/14
作	  者:	张存
邮 	  箱:	zhangcunliang@126.com

描	述：
记	录：
    2022.10.26 重新整理，替换IdentityHelper

***************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;

namespace ASmile.Helpers
{
    /// <summary>
    /// 中国大陆身份证号码解析
    /// </summary>
    public static class IDHelper
    {
        //系数要与17位身份相乘
        static readonly int[] Modulus = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };

        //被11整出计算出的数字 0-10(且只有可能是0-10 ,11个数字) 以此 对应 的数组 0-10元素值
        static readonly char[] CheckNo = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };
        /// <summary>
        /// 根据身份证号获取身份信息
        /// </summary>
        public static IDResult GetIDResult(string idStr)
        {
            idStr = idStr.ToUpper();
            IDResult ret = new IDResult();
            if (idStr.Length != 18)
            {
                ret.Msg = "长度不等于18,代码 01";
                goto RET;
            }
            if (!RegexHelper.Check(idStr, @"^[\dXx]{18}$"))
            {
                ret.Msg = "格式错误,代码 02";
                goto RET;
            }
            string birthdayStr = idStr.Substring(6, 8);
            if (DateTime.TryParseExact(birthdayStr, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture, System.Globalization.DateTimeStyles.AssumeLocal, out DateTime result))
            {
                ret.Birthday = result;
            }
            else
            {
                ret.Msg = "生日格式错误,代码 03";
                goto RET;
            }
            ret.Sex = Convert.ToInt32(idStr.Substring(14, 3)) % 2 == 0 ? "女" : "男";
            ret.AreaCode = idStr.Substring(0, 6);

            int tmpNo;
            int sumCHKNo = 0;
            for (int i = 0; i < idStr.Length - 1; i++)
            {
                tmpNo = int.Parse(idStr[i].ToString());
                sumCHKNo += Modulus[i] * tmpNo;
            }
            char okCode = CheckNo[sumCHKNo % 11];
            if (idStr[idStr.Length - 1] != okCode)
            {
                ret.Msg = $"校验码错误(正确值：{okCode}),代码 04";
                goto RET;
            }

            ret.OK = true;
            ret.Msg = "OK";

        RET:
            return ret;
        }
        /// <summary>
        /// 验证身份证号，并返回消息
        /// </summary>
        public static bool VerifyID(string idStr, out string msg)
        {
            var ret = GetIDResult(idStr);
            msg = ret.Msg;
            return ret.OK;
        }
        /// <summary>
        /// 验证身份证号
        /// </summary>
        public static bool VerifyID(string idStr)
        {
            return VerifyID(idStr, out _);
        }

    }
    /// <summary>
    /// 身份证结果信息
    /// </summary>
    public class IDResult
    {
        /// <summary>
        /// 解析成功返回true
        /// </summary>
        public bool OK { set; get; }
        /// <summary>
        /// 失败返回消息
        /// </summary>
        public string Msg { set; get; }
        /// <summary>
        /// 区域码要对应字典能得出区域名称
        /// </summary>
        public string AreaCode { set; get; }
        /// <summary>
        /// 性别，男|女
        /// </summary>
        public string Sex { set; get; }
        /// <summary>
        /// 生日
        /// </summary>
        public DateTime Birthday { set; get; }
    }
}
